home *** CD-ROM | disk | FTP | other *** search
- /*
- * Project: <none>
- *
- * Filename: DirectoryPopup.c
- *
- * Author: Marco Piovanelli
- *
- * Revision History:
- *
- * 1996.06.02 MP created this file
- *
- */
-
-
- #include "DirectoryPopup.h"
- #include "Utilities.h"
-
- #ifndef __FOLDERS__
- #include <Folders.h>
- #endif
-
- #ifndef __DEVICES__
- #include <Devices.h>
- #endif
-
- #ifndef __ICONS__
- #include <Icons.h>
- #endif
-
- #ifndef __GESTALT__
- #include <Gestalt.h>
- #endif
-
- #ifndef __TEXTUTILS__
- #include <TextUtils.h>
- #endif
-
- // private constants
-
- enum
- {
- kFinderIconIndicator = 0x1A , // menu item cmd for "Finder" icons
- kFinderIconBaseID = -4000 ,
- kStandardFileStrings = -6046 ,
- kIndTrashName = 2
- } ;
-
- OSType GetVolumeKind ( SInt16 inVolumeRefNum )
- {
- OSType volumeKind = 0 ;
- HParamBlockRec pb ;
- DCtlPtr pDCtlEntry ;
- DRVRHeaderPtr pDriver ;
-
- // get volume info
- BlockClear ( & pb, sizeof ( pb ) ) ;
- pb . volumeParam . ioVRefNum = inVolumeRefNum ;
- if ( PBHGetVInfoSync ( & pb ) == noErr )
- {
- // get a pointer to the driver control entry of the volume's driver
- pDCtlEntry = * GetDCtlEntry ( pb . volumeParam . ioVDRefNum ) ;
-
- // get a pointer to the driver itself
- pDriver = ( DRVRHeaderPtr ) pDCtlEntry -> dCtlDriver ;
-
- // if the driver is RAM-based, dCtlDriver is really a handle
- if ( pDCtlEntry -> dCtlFlags & dRAMBasedMask )
- {
- pDriver = * ( DRVRHeaderHandle ) pDriver ;
- }
-
- // extract driver "tag" from driver name (letters 2 to 5)
- volumeKind = * ( OSType * ) ( & pDriver -> drvrName [ 2 ] ) ;
- }
-
- return volumeKind ;
- }
-
- static Boolean HasModernStandardFile ( void )
- {
- SInt32 response ;
-
- return ( ( Gestalt ( gestaltStandardFileAttr, & response ) == noErr ) &&
- ( response & ( 1L << gestaltStandardFileHasDynamicVolumeAllocation ) ) ) ;
- }
-
- MenuRef BuildDirectoryPopup ( const FSSpec * inFileSpec )
- {
- MenuRef popup = nil ;
- FSSpec spec = * inFileSpec ;
- Str255 trashName ;
- SInt16 item ;
- SInt16 icon ;
- SInt32 desktopDirectory = 0 ;
- SInt32 trashDirectory = 0 ;
- SInt32 thisDirectory ;
- SInt32 trashNameLength ;
- SInt16 volume ;
- OSType volumeKind ;
- OSErr err ;
-
- // find the IDs of the desktop and trash directories for the specified volume
- FindFolder ( spec . vRefNum, kDesktopFolderType, kDontCreateFolder, & volume, & desktopDirectory ) ;
- FindFolder ( spec . vRefNum, kTrashFolderType, kDontCreateFolder, & volume, & trashDirectory ) ;
-
- // create an uninitialized menu from scratch
- if ( ( popup = NewMenu ( kDirectoryPopupMenuID, "\px" ) ) == nil )
- {
- return popup ;
- }
-
- item = 0 ;
- thisDirectory = -1 ;
- do
- {
- // add a new item to the menu
- item ++ ;
- AppendMenu ( popup, "\px" ) ;
-
- // find out which icon to use for this item
- if ( item == 1 )
- {
- // first item in the pop-up menu uses a document icon
- icon = kGenericDocumentIconResource ;
- }
- else if ( spec . parID == fsRtParID )
- {
- // use a disk icon for root level directory
- // default icon is the generic hard disk icon
- icon = kGenericHardDiskIconResource ;
-
- // find out volume kind
- volumeKind = GetVolumeKind ( spec . vRefNum ) ;
-
- // use special icons for floppy and file server volumes
- if ( ( volumeKind == kVolumeKindFloppy ) || ( volumeKind == kVolumeKindDiskImage ) )
- {
- icon = kFloppyIconResource ;
- }
- else if ( volumeKind == kVolumeKindFileServer )
- {
- icon = kGenericFileServerIconResource ;
- }
- else if ( HasModernStandardFile ( ) )
- {
- // the Standard File package that comes with System 7.0 Update 3.0
- // (built in System 7.5 and newer) has additional small icons
- // for CD-ROM and RAM disk volumes
- if ( volumeKind == kVolumeKindCDROM )
- {
- icon = kGenericCDROMIconResource ;
- }
- else if ( volumeKind == kVolumeKindRAMDisk )
- {
- icon = kGenericRAMDiskIconResource ;
- }
- }
- }
- else if ( thisDirectory == trashDirectory )
- {
- // if this directory is the trash directory, use the trash icon
- // and the real trash name
- icon = kTrashIconResource ;
- GetIndString ( trashName, kStandardFileStrings, kIndTrashName ) ;
- trashNameLength = StrLength ( trashName ) ;
- if ( ( trashNameLength > 0 ) && ( trashNameLength <= 63 ) )
- {
- BlockMoveData ( trashName, & spec . name, trashNameLength + 1 ) ;
- }
- }
- else
- {
- // in all other cases, use the open folder icon
- icon = kOpenFolderIconResource ;
- }
-
- // set name and icon of current Finder object
- SetMenuItemText ( popup, item, spec . name ) ;
- SetItemIcon ( popup, item, icon - kFinderIconBaseID ) ;
- SetItemCmd ( popup, item, kFinderIconIndicator ) ;
-
- // break out if we have reached a desktop child or the trash directory
- if ( ( spec . parID == desktopDirectory ) || ( thisDirectory == trashDirectory ) )
- {
- break ;
- }
-
- // otherwise, find the file specification of the parent directory
- thisDirectory = spec . parID ;
- err = FindParentSpec ( & spec ) ;
- }
- while ( err == noErr ) ;
-
- return popup ;
- }
-
- Boolean TrackDirectoryPopup ( FSSpec * ioFileSpec, WindowRef inWindow, Point inHitPt )
- {
- // call this function when you detect a command-click in a window's drag bar
- // on entry, ioFileSpec points to the file associated with the window
- // on exit, ioFileSpec points to the selected folder (if a selection was made)
- // if this function determines that this click should show a directory
- // pop-up menu, it displays it and does all the mouse tracking.
- // It then returns true if a selection was made.
-
- RgnHandle structureRgn ;
- SInt16 titleWidth ;
- Rect r ;
- Point popCorner ;
- MenuRef popup ;
- SInt16 menuChoice ;
-
- // make sure inWindow is selected
- if ( ! IsWindowHilited ( inWindow ) )
- {
- return false ;
- }
-
- if ( ( structureRgn = NewRgn ( ) ) == nil )
- {
- return false ; // emergency exit
- }
- GetWindowStructureRgn ( inWindow, structureRgn ) ;
- r = ( * structureRgn ) -> rgnBBox ;
- DisposeRgn ( structureRgn ) ;
- titleWidth = GetWindowTitleWidth ( inWindow ) ;
- popCorner . v = r . top + 1 ;
- popCorner . h = r . left + ( ( ( r . right - r . left ) - titleWidth + 1 ) / 2 ) - 23 ;
- if ( ( inHitPt . h < popCorner . h + 16 ) || ( inHitPt . h > popCorner . h + titleWidth + 28 ) )
- {
- return false ;
- }
-
- // build the directory pop-up menu
- if ( ( popup = BuildDirectoryPopup ( ioFileSpec ) ) == nil )
- {
- return false ;
- }
-
- // insert the menu into the hierarchical portion of the menu list
- InsertMenu ( popup, -1 ) ;
-
- // pop up the menu
- menuChoice = ( SInt16 ) PopUpMenuSelect ( popup, popCorner . v, popCorner . h, 1 ) ;
-
- // remove the pop-up menu from the menu list
- DeleteMenu ( kDirectoryPopupMenuID ) ;
-
- // dispose of the menu itself
- DisposeMenu ( popup ) ;
-
- // see if an item up in the hierarchy was selected
- if ( menuChoice > 1 )
- {
- for ( ; menuChoice > 1 ; menuChoice -- )
- {
- FindParentSpec ( ioFileSpec ) ;
- }
- return true ;
- }
-
- return false ;
- }
-